﻿using System;
using System.Collections.Generic;

namespace AppMain
{
    public struct Vec2 : IEquatable<Vec2>
    {
        public Vec2(float x, float y) { this.x = x; this.y = y; }

        public float x;
        public float y;

        public override string ToString()
        {
            return string.Format("x: {0}  y: {1}", x, y);
        }

        public static float Dot(Vec2 lhs, Vec2 rhs) { return lhs.x * rhs.x + lhs.y * rhs.y; }
        public float magnitude { get { return (float)Math.Sqrt(x * x + y * y); } }
        public void Normalize()
        {
            float mag = magnitude;
            if (mag > kEpsilon)
                this = this / mag;
            else
                this = zero;
        }

        // Returns this vector with a ::ref::magnitude of 1 (RO).
        public Vec2 normalized
        {
            get
            {
                Vec2 v = new Vec2(x, y);
                v.Normalize();
                return v;
            }
        }

        // used to allow Vector2s to be used as keys in hash tables
        public override int GetHashCode()
        {
            return x.GetHashCode() ^ (y.GetHashCode() << 2);
        }


        // also required for being able to use Vector2s as keys in hash tables
        public override bool Equals(object other)
        {
            if (!(other is Vec2)) return false;

            return Equals((Vec2)other);
        }

        public bool Equals(Vec2 other)
        {
            return x == other.x && y == other.y;
        }

        // Adds two vectors.
        public static Vec2 operator +(Vec2 a, Vec2 b) { return new Vec2(a.x + b.x, a.y + b.y); }
        // Subtracts one vector from another.
        public static Vec2 operator -(Vec2 a, Vec2 b) { return new Vec2(a.x - b.x, a.y - b.y); }
        // Multiplies one vector by another.
        public static Vec2 operator *(Vec2 a, Vec2 b) { return new Vec2(a.x * b.x, a.y * b.y); }
        // Divides one vector over another.
        public static Vec2 operator /(Vec2 a, Vec2 b) { return new Vec2(a.x / b.x, a.y / b.y); }
        // Negates a vector.
        public static Vec2 operator -(Vec2 a) { return new Vec2(-a.x, -a.y); }
        // Multiplies a vector by a number.
        public static Vec2 operator *(Vec2 a, float d) { return new Vec2(a.x * d, a.y * d); }
        // Multiplies a vector by a number.
        public static Vec2 operator *(float d, Vec2 a) { return new Vec2(a.x * d, a.y * d); }
        // Divides a vector by a number.
        public static Vec2 operator /(Vec2 a, float d) { return new Vec2(a.x / d, a.y / d); }
        public static bool operator ==(Vec2 lhs, Vec2 rhs)
        {
            // Returns false in the presence of NaN values.
            float diff_x = lhs.x - rhs.x;
            float diff_y = lhs.y - rhs.y;
            return (diff_x * diff_x + diff_y * diff_y) < kEpsilon * kEpsilon;
        }

        // Returns true if vectors are different.
        public static bool operator !=(Vec2 lhs, Vec2 rhs)
        {
            // Returns true in the presence of NaN values.
            return !(lhs == rhs);
        }

        // *Undocumented*
        public const float kEpsilon = 0.00001F;
        // *Undocumented*
        public const float kEpsilonNormalSqrt = 1e-15f;

        static readonly Vec2 zeroVector = new Vec2(0F, 0F);
        static readonly Vec2 oneVector = new Vec2(1F, 1F);
        static readonly Vec2 upVector = new Vec2(0F, 1F);
        static readonly Vec2 downVector = new Vec2(0F, -1F);
        static readonly Vec2 leftVector = new Vec2(-1F, 0F);
        static readonly Vec2 rightVector = new Vec2(1F, 0F);

        public static Vec2 zero { get { return zeroVector; } }
        // Shorthand for writing @@Vector2(1, 1)@@
        public static Vec2 one { get { return oneVector; } }
        // Shorthand for writing @@Vector2(0, 1)@@
        public static Vec2 up { get { return upVector; } }
        // Shorthand for writing @@Vector2(0, -1)@@
        public static Vec2 down { get { return downVector; } }
        // Shorthand for writing @@Vector2(-1, 0)@@
        public static Vec2 left { get { return leftVector; } }
        // Shorthand for writing @@Vector2(1, 0)@@
        public static Vec2 right { get { return rightVector; } }
    }
}
